// java_demo.java - SecureConfig命令行工具的Java演示程序
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * SecureConfig命令行工具的Java演示程序
 * 
 * 注意: 此程序依赖Jackson库来处理JSON
 * 请确保添加以下依赖到您的Maven pom.xml或Gradle构建文件:
 * 
 * Maven:
 * <dependency>
 *     <groupId>com.fasterxml.jackson.core</groupId>
 *     <artifactId>jackson-databind</artifactId>
 *     <version>2.13.0</version>
 * </dependency>
 * 
 * Gradle:
 * implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.0'
 */
public class java_demo {
    private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
    private static final String ANSI_RESET = "\u001B[0m";
    private static final String ANSI_RED = "\u001B[31m";
    private static final String ANSI_GREEN = "\u001B[32m";
    private static final String ANSI_YELLOW = "\u001B[33m";
    private static final String ANSI_CYAN = "\u001B[36m";

    public static void main(String[] args) {
        try {
            // 计时开始
            long startTime = System.currentTimeMillis();

            // 设置主密钥环境变量 - 在系统环境或启动脚本中设置更安全
            // 这里仅作演示，实际使用时应通过更安全的方式提供密钥
            ProcessBuilder envBuilder = new ProcessBuilder();
            Map<String, String> env = envBuilder.environment();
            env.put("SECURECONFIGMASTERKEY", "your_master_key_here");

            System.out.println(ANSI_CYAN + "\n===== 第一部分: 常规加解密操作 =====" + ANSI_RESET);

            // 1. 创建 json 配置文件
            String jsonName = "demo_json";
            System.out.println("创建 json 配置文件: " + jsonName);
            Map<String, Object> result = runSecureCommand("create", jsonName, "--type", "json", "--force");
            printResult("创建 json 配置", result);

            // 2. set-value 仅支持 json
            System.out.println("设置 json 配置的值: " + jsonName + " app.version = 2.0.0");
            result = runSecureCommand("set-value", jsonName, "app.version", "2.0.0");
            printResult("设置 json 配置值", result);

            // 3. get-value 仅支持 json
            System.out.println("获取 json 配置的值: " + jsonName + " app.version");
            result = runSecureCommand("get-value", jsonName, "app.version");
            printResult("获取 json 配置值", result);

            // 4. 创建 text 文件
            String textName = "demo_text";
            System.out.println("创建 text 文件: " + textName);
            result = runSecureCommand("create", textName, "--type", "text", "--force");
            printResult("创建 text 文件", result);

            // 5. 保存明文内容到 text 文件（直接写入文件）
            Path textPath = Paths.get("configs", textName + ".txt");
            try {
                Files.createDirectories(textPath.getParent());
                Files.write(textPath, "Hello, SecureConfig!\n这是一个文本文件。".getBytes(StandardCharsets.UTF_8));
                System.out.println("已写入明文内容到 " + textPath);
            } catch (IOException e) {
                System.err.println(ANSI_RED + "写入文件失败: " + e.getMessage() + ANSI_RESET);
                return;
            }

            // 6. 加密 text 文件
            System.out.println("加密 text 文件: " + textName);
            result = runSecureCommand("encrypt", textName, "--type", "text");
            printResult("加密 text 文件", result);

            // 7. 解密 text 文件
            System.out.println("解密 text 文件: " + textName);
            result = runSecureCommand("decrypt", textName, "--type", "text");
            printResult("解密 text 文件", result);

            // 8. 创建 binary 文件
            String binaryName = "demo_bin";
            System.out.println("创建 binary 文件: " + binaryName);
            result = runSecureCommand("create", binaryName, "--type", "binary", "--force");
            printResult("创建 binary 文件", result);

            // 9. 保存明文内容到 binary 文件（写入二进制数据）
            Path binaryPath = Paths.get("configs", binaryName + ".bin");
            try {
                Files.createDirectories(binaryPath.getParent());
                byte[] binaryData = {0, 1, 2, 3, 4, 5, 6, 7};
                Files.write(binaryPath, binaryData);
                System.out.println("已写入明文内容到 " + binaryPath);
            } catch (IOException e) {
                System.err.println(ANSI_RED + "写入文件失败: " + e.getMessage() + ANSI_RESET);
                return;
            }

            // 10. 加密 binary 文件
            System.out.println("加密 binary 文件: " + binaryName);
            result = runSecureCommand("encrypt", binaryName, "--type", "binary");
            printResult("加密 binary 文件", result);

            // 11. 解密 binary 文件
            System.out.println("解密 binary 文件: " + binaryName);
            result = runSecureCommand("decrypt", binaryName, "--type", "binary");
            printResult("解密 binary 文件", result);

            System.out.println(ANSI_CYAN + "\n===== 第二部分: 原地加解密操作 (使用 --inplace 参数) =====" + ANSI_RESET);

            // 12. 创建原地加密演示文件
            String inplaceName = "inplace_demo";
            Path jsonPath = Paths.get("configs", inplaceName + ".json");
            Path backupPath = Paths.get("configs", inplaceName + "_backup.json");

            System.out.println("创建原地加密演示 json 文件: " + inplaceName);
            result = runSecureCommand("create", inplaceName, "--type", "json", "--force");
            printResult("创建原地加密演示文件", result);

            // 13. 设置演示文件内容
            System.out.println("设置演示文件值: " + inplaceName);
            runSecureCommand("set-value", inplaceName, "demo.name", "原地加密演示");
            result = runSecureCommand("set-value", inplaceName, "demo.description", "这是一个测试原地加密功能的文件");

            // 14. 解密后备份原始明文文件（用于对比）
            result = runSecureCommand("decrypt", inplaceName, "--type", "json");
            try {
                Files.copy(jsonPath, backupPath, StandardCopyOption.REPLACE_EXISTING);
                System.out.println("已备份明文文件到 " + backupPath);
            } catch (IOException e) {
                System.err.println(ANSI_RED + "备份文件失败: " + e.getMessage() + ANSI_RESET);
            }
            printResult("设置演示文件值", result);

            // 15. 原地加密
            System.out.println("原地加密文件: " + inplaceName + " (使用 --inplace 参数)");
            result = runSecureCommand("encrypt", inplaceName, "--type", "json", "--inplace");
            printResult("原地加密", result);

            // 16. 验证原地加密结果
            boolean encryptedJsonExists = Files.exists(Paths.get("configs", inplaceName + ".json.enc"));
            boolean originalJsonExists = Files.exists(jsonPath);
            System.out.println("加密文件 (" + inplaceName + ".json.enc) 是否存在? " + encryptedJsonExists);
            System.out.println("原始文件 (" + inplaceName + ".json) 是否存在? " + originalJsonExists + " (原地加密，应该存在)");

            // 17. 原地解密
            System.out.println("原地解密文件: " + inplaceName + " (使用 --inplace 参数)");
            result = runSecureCommand("decrypt", inplaceName, "--type", "json", "--inplace");
            printResult("原地解密", result);

            // 18. 验证文件是否相同
            boolean areFilesIdentical = false;
            try {
                byte[] file1Content = Files.readAllBytes(jsonPath);
                byte[] file2Content = Files.readAllBytes(backupPath);
                areFilesIdentical = Arrays.equals(file1Content, file2Content);
            } catch (IOException e) {
                System.err.println(ANSI_RED + "比较文件时出错: " + e.getMessage() + ANSI_RESET);
            }
            System.out.println("原地加解密后的文件与原始文件是否相同? " + areFilesIdentical);

            // 19. 清理演示文件
            System.out.println(ANSI_CYAN + "\n===== 清理演示文件 =====" + ANSI_RESET);
            List<String> filesToDelete = Arrays.asList(jsonName, textName, binaryName, inplaceName);

            for (String name : filesToDelete) {
                System.out.println("删除文件: " + name);
                runSecureCommand("delete", name, "--type", "json");
            }

            if (Files.exists(backupPath)) {
                try {
                    Files.delete(backupPath);
                    System.out.println("已删除备份文件: " + backupPath);
                } catch (IOException e) {
                    System.err.println(ANSI_RED + "删除备份文件失败: " + e.getMessage() + ANSI_RESET);
                }
            }

            // 20. 演示 get-value/set-value 仅支持 json 的限制
            System.out.println(ANSI_CYAN + "\n===== 演示 get-value/set-value 仅支持 json 的限制 =====" + ANSI_RESET);

            System.out.println("尝试对 text 文件使用 get-value (应报错)");
            try {
                result = runSecureCommand("get-value", textName, "app.version", "--type", "text");
            } catch (Exception e) {
                result = Map.of("status", "error", "message", e.getMessage());
            }
            printResult("get-value 用于 text 类型", result);

            System.out.println("尝试对 binary 文件使用 get-value (应报错)");
            try {
                result = runSecureCommand("get-value", binaryName, "app.version", "--type", "binary");
            } catch (Exception e) {
                result = Map.of("status", "error", "message", e.getMessage());
            }
            printResult("get-value 用于 binary 类型", result);

            // 计算总耗时
            long endTime = System.currentTimeMillis();
            double totalTime = (endTime - startTime) / 1000.0;
            System.out.println(ANSI_GREEN + "\n全部演示完成，总耗时: " + String.format("%.2f", totalTime) + " 秒" + ANSI_RESET);

        } catch (Exception e) {
            System.err.println(ANSI_RED + "执行程序时发生错误: " + e.getMessage() + ANSI_RESET);
            e.printStackTrace();
        }
    }

    /**
     * 执行 SecureConfig 命令并返回结果
     */
    @SuppressWarnings("unchecked")
    private static Map<String, Object> runSecureCommand(String command, String... args) throws Exception {
        List<String> cmdList = new ArrayList<>();
        cmdList.add("secureconfig");
        cmdList.add(command);
        cmdList.add("-f");
        cmdList.add("json");
        
        for (String arg : args) {
            cmdList.add(arg);
        }
        
        System.out.println(ANSI_YELLOW + "执行命令: " + String.join(" ", cmdList) + ANSI_RESET);
        
        ProcessBuilder pb = new ProcessBuilder(cmdList);
        Process process = pb.start();
        
        try (BufferedReader stdOutReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
             BufferedReader stdErrReader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
            
            StringBuilder output = new StringBuilder();
            String line;
            while ((line = stdOutReader.readLine()) != null) {
                output.append(line);
            }
            
            StringBuilder errorOutput = new StringBuilder();
            while ((line = stdErrReader.readLine()) != null) {
                errorOutput.append(line);
            }
            
            int exitCode = process.waitFor();
            
            String result = output.toString();
            // 处理可能的非JSON前缀
            int jsonStart = result.indexOf('{');
            if (jsonStart >= 0) {
                result = result.substring(jsonStart);
            }
            
            if (exitCode == 0) {
                return JSON_MAPPER.readValue(result, Map.class);
            } else {
                if (result.trim().isEmpty() && !errorOutput.toString().trim().isEmpty()) {
                    return Map.of("status", "error", "message", errorOutput.toString().trim());
                }
                
                try {
                    return JSON_MAPPER.readValue(result, Map.class);
                } catch (Exception e) {
                    return Map.of("status", "error", "message", "执行命令失败，退出码: " + exitCode);
                }
            }
        }
    }
    
    /**
     * 打印结果
     */
    private static void printResult(String title, Map<String, Object> result) {
        System.out.println(ANSI_CYAN + "\n==== " + title + " ====" + ANSI_RESET);
        if ("success".equals(result.get("status"))) {
            try {
                System.out.println(JSON_MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(result));
            } catch (Exception e) {
                System.out.println(result);
            }
        } else {
            System.out.println(ANSI_RED + "失败: " + result.get("message") + ANSI_RESET);
        }
    }
}

/*
使用方法:
1. 确保已安装SecureConfig工具
2. 确保已安装Java和Jackson库
3. 编译: javac -cp jackson-databind-2.13.0.jar:jackson-core-2.13.0.jar:jackson-annotations-2.13.0.jar java_demo.java
4. 运行: java -cp .:jackson-databind-2.13.0.jar:jackson-core-2.13.0.jar:jackson-annotations-2.13.0.jar java_demo
*/ 
*/ 